#include "original_modified_io.h"
#include "logger.h"
#include "samples_preprocessor.h"

COriginalModifiedIO::COriginalModifiedIO(ISampleIO *pOriginalIO, ISampleIO *pModifiedIO)
		:mError(true),
		mUseOriginalForRead(true),
		mOriginalIO(pOriginalIO),
		mModifiedIO(pModifiedIO)
{
}

COriginalModifiedIO::~COriginalModifiedIO()
{
	if(mOriginalIO) {
		delete mOriginalIO;
	}
	if(mModifiedIO) {
		delete mModifiedIO;
	}
}

int COriginalModifiedIO::init(CPropertiesReader *pConfig)
{
	// first init run, mError must be true and will be set to false if all is ok
	if(!mError) {
		printl(LL_WARN, __FILE__, "is already init.\n");
		return 0;
	}

	if(!mOriginalIO || !mModifiedIO) {
		return -1;
	}

	if(mOriginalIO->init(pConfig) != 0) {
		return -1;
	}
	if(mModifiedIO->init(pConfig) != 0) {
		return -1;
	}

	if((mOriginalIO->getStreamInfo().mSampleRate
	!= mModifiedIO->getStreamInfo().mSampleRate)
	|| (mOriginalIO->getStreamInfo().mSamplesWidth
	!= mModifiedIO->getStreamInfo().mSamplesWidth)
	|| (mOriginalIO->getStreamInfo().mCodec
	!= mModifiedIO->getStreamInfo().mCodec)) {
		printl(LL_ERR, __FILE__, "Doesn't support different stream infos.\n");
		return -1;
	}
	mError = false;
	return 0;
}

int COriginalModifiedIO::destroy()
{
	bool lDestroyError(false);
	if(mOriginalIO) {
		if(mOriginalIO->destroy() != 0) {
			lDestroyError = true;
		}
	}
	if(mModifiedIO) {
		if(mModifiedIO->destroy() != 0) {
			lDestroyError = true;
		}
	}
	if(lDestroyError) {
		return -1;
	}
	return 0;
}

int COriginalModifiedIO::read(void** pData, EAction& pAction, int pTimeout)
{
	if(mError) {
		return -1;
	}
	if(mUseOriginalForRead) {
		mUseOriginalForRead = false;
		int rv = mOriginalIO->read(pData, pAction, pTimeout);
		if(rv < 0) {
			return -1;
		}
		if(pAction != EMBED) {
			printl(LL_ERR, __FILE__, "Read from OriginalIO doesn't set action to EMBED.\n");
			return -1;
		}
		return rv;
	}
	else {
		mUseOriginalForRead = true;
		int rv = mModifiedIO->read(pData, pAction, pTimeout);
		if(rv < 0) {
			return -1;
		}
		if(pAction != EXTRACT) {
			printl(LL_ERR, __FILE__, "Read from ModifiedIO doesn't set action to EXTRACT.\n");
			return -1;
		}
		return rv;
	}
}

int COriginalModifiedIO::write(void* pData, const EAction& pAction, int pLength)
{
	if(mError) {
		return -1;
	}
	switch(pAction) {
		case EMBED:
			// secret infos are embedded -> write to modified io
			return mModifiedIO->write(pData, pAction, pLength);
		case EXTRACT:
			// secret infos are extracted -> write to original io
			return mOriginalIO->write(pData, pAction, pLength);
		default:
			printl(LL_ERR, __FILE__, "Write only support EMBED or EXTRACT.\n");
			return -1;
	}
	return -1;
}

NAudioFormats::SStreamInfo COriginalModifiedIO::getStreamInfo()
{
	if(mError) {
		printl(LL_WARN, __FILE__, "Internal error. No stream infos.\n");
		return NAudioFormats::SStreamInfo(NAudioFormats::UNKNOWN_WIDTH,
				0,
				NAudioFormats::UNKNOWN_CODEC);
	}
	// stream infos from original and modified io are the same. ->
	// return original (could also be from modified, no difference)
	return mOriginalIO->getStreamInfo();
}
